use crate::config::Config;
use crate::{data, get_addr_v6};
use rand::Rng;
use socket2::{Domain, SockAddr, Socket, Type};
use std::error::Error;
use std::net::SocketAddr;
use std::time::Duration;
use tokio::io::{copy_bidirectional as data_forward, AsyncReadExt, AsyncWriteExt};
use tokio::net::{TcpListener, TcpStream};
use tokio::time::sleep;
use tracing::{error, info};

fn get_port() -> u16{
    rand::rng().random_range(50000..60000)
}


fn get_listen(addr:SocketAddr) -> Result<TcpListener,Box<dyn Error>>{
    let socket = Socket::new(Domain::IPV6, Type::STREAM, None)?;
    // 使用tokio配合socket2，需要注意的，要将socket设置为非阻塞，用tokio-》form_std
    socket.set_nonblocking(true)?;
    socket.set_reuse_address(true)?;
    // 添加linux系统端口复用，window没有该功能
    #[cfg(unix)]
    socket.set_reuse_port(true)?;
    socket.bind(&SockAddr::from(addr))?;
    socket.listen(128)?;
    let listener = TcpListener::from_std(socket.into())?;
    Ok(listener)
}


async fn listener_handle(listener:TcpListener,config:&Config) -> Result<(),Box<dyn Error>>{
    loop {
        let (mut stream, addr) = listener.accept().await?;
        info!("客户端连接：{}", addr);
        let addr = format!("{}:{}", config.client.bind_addr,config.client.bind_port);
        tokio::spawn(async move{
            match TcpStream::connect(addr).await {
                Ok(mut remote) => {
                    info!("本地连接已建立，准备转发");
                    if let Err(e) = data_forward(&mut stream,&mut remote).await{
                        error!("端口转发错误{e}");
                        return;
                    }
                }
                Err(e) => {
                    error!("本地连接建立失败：{e}")
                }
            };

        });
    }
}

async fn get_stream(addr:SocketAddr,config: &Config) -> Result<TcpStream,Box<dyn Error>>{
    let socket = Socket::new(Domain::IPV6, Type::STREAM, None)?;
    socket.set_reuse_address(true)?;
    // 不能在连接建立之前使用非阻塞
    // socket.set_nonblocking(true)?;
    #[cfg(unix)]
    socket.set_reuse_port(true)?;
    socket.bind(&SockAddr::from(addr))?;
    let remote_addr = get_addr_v6(&config.server.address, config.server.port).await?;
    socket.connect(&remote_addr.into())?;
    let stream = TcpStream::from_std(socket.into())?;
    Ok(stream)
}


async fn stream_handle(mut stream:TcpStream,config:&Config) -> Result<(),Box<dyn Error>>{
    data::set_auth(&mut stream,config).await;
    let (mut read_half,mut write_half) = stream.into_split();
    tokio::spawn(async move{
        loop {
            if let  Err(e) = write_half.write_all(b"ping").await{
                error!("ping err: {e}");
                return;
            }
            sleep(Duration::from_secs(10)).await;
        }
    });

    tokio::spawn(async move{
        let mut buf = [0;512];
        loop {
            match read_half.read(&mut buf).await {
                Ok(0) => return,
                Ok(len) => {
                    let rep = String::from_utf8_lossy(&buf[..len]);
                    info!("stream_handle read rep is {rep}")
                }
                Err(e) => {
                    error!("stream_handle read err:{e}");
                    return
                }
            }
        }
    });

    Ok(())
}
async fn run(config: Config) -> Result<(),Box<dyn Error>> {

    // 异步线程
    let mut handles = vec![];

    let port = get_port();
    info!("端口分配在：{}",port);

    let local_addr = format!("[::]:{}", port).parse::<SocketAddr>().unwrap();

    let listener = get_listen(local_addr)?;
    info!("本地监听端口 {} 等待连接...", port);


    let config_clone = config.clone();
    let listener_handle = tokio::spawn(async move {
        if let Err(e) = listener_handle(listener,&config_clone).await{
            error!("listener_handle err: {e}")
        }
    });
    handles.push(listener_handle);


    let stream = get_stream(local_addr,&config).await?;
    stream_handle(stream,&config).await?;


    for handle in handles {
        handle.await?;
    }
    Ok(())
}

pub async fn start(config: Config){
    if let Err(e) = run(config).await{
        error!("start err:{e}")
    }
}